package com.suxin.thread.schedule;

import com.suxin.thread.schedule.domain.TaskStatus;
import com.suxin.thread.schedule.domain.TaskWithBlobs;
import com.suxin.thread.schedule.job.Job;
import com.suxin.thread.schedule.job.JobService;
import com.suxin.thread.schedule.task.Task;
import com.suxin.thread.schedule.task.TaskService;
import com.suxin.thread.schedule.utils.RedisUtils;

import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * @author Tang
 * @classname RunnableJob
 * @description [  ]
 * @date 2021/3/16 10:58
 */
public class RunnableJob implements Runnable,LifeCycle{

    private static final String LOCK_PREFIX = "L:T";

    public Job job;

    public JobService jobService;

    public TaskService taskService;

    public RedisUtils redisUtils;

    public RunnableJob(JobService jobService, TaskService taskService, Job job) {
        this.job = job;
        this.jobService = jobService;
        this.taskService = taskService;
    }

    @Override
    public void run() {
        this.before();
        // 获取job任务流下面对应的子任务
        List<TaskWithBlobs> tQ = taskService.findAll(this.job.getId());
        Set<TaskWithBlobs> fQ = new HashSet<>(8);
        CountDownLatch countDownLatch = new CountDownLatch(tQ.size());
        // fQ:完成队列，tQ:任务队列
        while (tQ.size() != fQ.size()) {
            for (TaskWithBlobs task : tQ) {
                if (fQ.contains(task)) {
                    continue;
                }
                String key = LOCK_PREFIX + task.getId(), cId = UUID.randomUUID().toString();
                boolean success = redisUtils.lock(key,2000,cId);
                if (success) {
                    // 重新获取 task
                    Task dbTask = taskService.find(task.getId());
                    if (dbTask != null || !dbTask.getVersion().equals(task.getVersion())) {
                        // 版本号不一致，更新版本号至最新，放入已完成队列
                        task.setVersion(dbTask.getVersion());
                        task.setUtcUpdate(dbTask.getUtcUpdate());
                        fQ.add(task);
                        redisUtils.release(key);
                        continue;
                    }
                    // 检查前置任务：preIsNull || preIsDone
                    if (isPreTaskDone()) {
                        RunnableTask rt = new RunnableTask(task,taskService,countDownLatch);
                        // WorkExecutor 线程
                        WorkExecutor.exec(rt);
                        fQ.add(task);
                    }
                    redisUtils.release(key);
                }
                // 获取锁失败，等待下一轮调度
            }
        }
        this.after();
    }

    private boolean isPreTaskDone() {
        return false;
    }

    @Override
    public void before() {
        job.setStatus(TaskStatus.RUNNING);
        job.setUtcUpdate(new Date());
        job.setVersion(job.getVersion() + 1);
        jobService.update();
    }

    @Override
    public void after() {
        job.setStatus(TaskStatus.SUCCESS);
        jobService.update();
    }
}